#include "precompiled.h"
#include "IMLGenerator.h"

namespace IcyCrystal {
	int IMLGenerator::getRegisterFromSymbol(Symbol* sym){
		LocationList::iterator it;
		for( it = sym->locations->begin(); it!= sym->locations->end(); it++){
			Arg* arg = *it;
			if( arg->arg == REGISTER ){
				return arg->name.intName;
			}
		}

		return -1;
	}

	void IMLGenerator::clearAllRegisters(){
		for( int i= 0; i < 5; i++ ){
			registerArray[i].variables->clear();
		}
	}	

	void IMLGenerator::removeRegisterFromSymbol( Symbol* sym, int reg){
		LocationList::iterator it;
		for( it = sym->locations->begin(); it!= sym->locations->end(); it++){
			Arg* arg = *it;
			if( arg->arg == REGISTER && arg->name.intName == reg ){
				sym->locations->erase(it);
				break;
			}
		}
	}

	bool IMLGenerator::symbolIsInRegister(Symbol* sym, int reg ){
		SymbolList::iterator it;
		for( it = registerArray[reg].variables->begin(); it!= registerArray[reg].variables->end(); it++){
			Symbol* theOther = *it;
			if( theOther->symbolName.compare(sym->symbolName) == 0)
				return true;
		}

		return false;
	}

	int IMLGenerator::getEmptyRegister(){
		for( int i =0; i < 5; i++){
			if( registerArray[i].variables->size() == 0 )
				return i;
		}
		return -1;
	}


	ArgList* IMLGenerator::getRegister(Symbol* sym, Quad& statement, UseMap& useMap, int statementNumber, int &out){

		/*If y is currently in a register, pick a register already containing y as R,.
		Do not issue a machine instruction to load this register, as none is needed.*/
		int x = getRegisterFromSymbol(sym);
		if( x != -1 ){
			out = x;
			return NULL;
		}

		/*If y is not in a register, but there is a register that is currently empty,
		pick one such register as Ry.*/
		x = getEmptyRegister();
		if( x != -1 ){
			out = x;
			return NULL;
		}

		// Difficult case: Need to pick optimal register
		// Loop the registers.
		ArgList spillInstructions[5];	// Containing arguments for each spill.
		
		for( int i = 0; i < 5; i++){
			for( int y = 0; y < registerArray[i].variables->size(); y++){
				Symbol* v = registerArray[i].variables->at(y);
				// Is V stored in another location?
				if( v->locations->size() > 1 )
					continue; 	// We are ok.
				else if( &v->symbolName == statement.inner.normalOp.result.name.symbolName &&
				&v->symbolName != statement.inner.normalOp.arg1.name.symbolName &&
				&v->symbolName != statement.inner.normalOp.arg2.name.symbolName){

					// v is the target and none of the arguments. We are ok.
					continue;
				}
				// Is V used later?
				else if(useMap[&v->symbolName].lastUse < statementNumber ){
					// We're Ok.
					continue;
				}
				else {
					// Spill the register.
					spillInstructions[i].push_back(generateStoreQuad(v,i));
				}
			}	
		}

		// Select the best register.
		int lowestCount = 100000;
		int lowestIndex = -1;
		for( int i = 0; i < 5; i++){
			if( spillInstructions[i].size() == 0 ){
				out = i;
				return NULL;
			}
			else if( spillInstructions[i].size() < lowestCount){
				lowestCount = spillInstructions[i].size();
				lowestIndex = i;
			}
		}

		// Return the one with the lowest count.
		out = lowestIndex;
		ArgList* newArg = new ArgList(spillInstructions[lowestIndex]);
		return newArg;
	}

	void IMLGenerator::removeRegisterFromAllSymbols(Namespace* currentNamespace, int reg, Symbol* except){
		_symbolMap::iterator it;
		for( it = currentNamespace->SymbolMap.begin(); it!= currentNamespace->SymbolMap.end(); it++){
			Symbol* sym = it->second;
			if( sym != except )
				removeRegisterFromSymbol(sym,reg);
		}
	}
};
